<template>
    <view>
        <!-- vant 上传组件，用来图片多选 -->
        <van-uploader
            class="upload-border"
            :accept="accept"
            :file-list="fileList"
            :deletable="!disabled"
            :disabled="disabled"
            @after-read="_afterRead"
            @delete="deleteImg"
            :multiple="true"
            :max-count="maxCount"
            :capture="capture"
            image-fit="none"
            :upload-icon="uploadIcon"
        ></van-uploader>
           <view style="position: absolute;top: -999999px;"> //把canvas移出视窗
                <view>
                    <canvas :style="{'width':canvasWidth+'px','height': canvasHeight+'px'}" canvas-id="myCanvas"></canvas>
               </view>
            </view>
    </view>
</template>

<script>
import uploadImage from '@/utils/js_sdk/yushijie-ossutil/ossutil/uploadFile.js';
// 以下路径需根据项目实际情况填写
import { pathToBase64, base64ToPath } from '@/utils/js_sdk/mmmm-image-tools/index.js';

export default {
    props: {
        // 是否禁用
        disabled: {
            type: Boolean,
            default: false
        },
        // 上传最大张数
        maxCount: {
            type: Number,
            default: 4
        },
        // 是否上传至oss
        isUploaderOss: {
            type: Boolean,
            default: false
        },
        // 图片数组
        photoList: {
            type: Array,
            default: () => []
        },
        // 图片或者视频选取模式
        capture: {
            type: Array,
            default: () => {
                return ['album', 'camera'];
            }
        },
        // 接受的文件类型, 可选值为all media image file video
        accept: {
            type: String,
            default: 'image'
        },
        // 图片上传到 OSS 服务上的存储目录
        ossPathPrefix: {
            type: String,
            default: 'yzom_img/APPLET/'
        },
        // 上传图标
        uploadIcon: {
            type: String,
            default: 'photograph'
        },
        // 是否需要压缩
        isCompress: {
            type: Boolean,
            default: true
        },
        // 文件上传大小限制，单位 byte
        compressMaxSize: {
            type: [Number, String],
            default: 1024 * 1024
        },
        // 图片压缩质量，0～100，数值越小，质量越低，压缩率越高
        quality: {
            type: Number,
            default: 80
        },
        // 图片是否添加水印
        isAddWaterMark: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            fileQuality: null,
            canvasWidth: '',
            canvasHeight: ''
        };
    },
    computed: {
        fileList: {
            get() {
                // console.log('photoList---', this.photoList);
                return this.photoList;
            },
            set(val) {
                this.$emit('uploadSuccess', val);
            }
        }
    },
    methods: {
        _afterRead(event) {
            const { file } = event.detail;
            // console.log('file---', file);
            // 图片要进行压缩及添加水印
            if (this.accept === 'image') {
                this.afterRead(file);
            } else {
                this.afterReadVideo(file);
            }
        },
        // 视频上传视频只用进行压缩
        async afterReadVideo(file) {
            const files = [];
            for (let i = 0; i < file.length; i++) {
                const ele = file[i];
                // files.push(this.addWaterMark(ele.url));
                if (this.isCompress) {
                    await this.videoCompress(ele).then(res => {
                        // console.log('压缩返回---', res);
                        files.push(res);
                    });
                } else {
                    files.push(ele);
                }
                Promise.all(files).then(res => {
                    console.log('返回成功', res);
                    uni.hideLoading();
                    const that = this;
                    uni.showLoading({
                        title: '上传中...'
                    });
                    this.uploadImage(res);
                });
            }
        },
        // 图片上传
        async afterRead(file) {
            const files = [];
            // console.log(file);
            this.fileQuality = this.quality;
            for (let i = 0; i < file.length; i++) {
                const ele = file[i];
                // files.push(this.addWaterMark(ele.url));
                if (this.isCompress) {
                    if (this.isAddWaterMark) {
                        // 添加水印返回
                        await this.addWaterMark(ele.url).then(res => {
                            // console.log('添加水印返回---', res);
                            files.push(res);
                        });
                    } else {
                        // 压缩返回
                        await this.imgCompress(ele).then(res => {
                            // console.log('压缩返回---', res);
                            files.push(res);
                        });
                    }
                } else {
                    if (this.isAddWaterMark) {
                        await this.addWaterMark(ele.url).then(res => {
                            files.push(res);
                        });
                    } else {
                        files.push(ele);
                    }
                }
            }
            Promise.all(files).then(res => {
                // console.log('返回成功', res);
                uni.hideLoading();
                const that = this;
                uni.showLoading({
                    title: '上传中...'
                });
                this.uploadImage(res);
            });
        },
        // 上传图片
        uploadImage(file) {
            const that = this,
                uploadPromiseTask = [], // 定义上传的promise任务栈,线上图片
                filePromiseTask = []; // 本地图片
            this.$emit('afterRead', file);
            for (let i = 0; i < file.length; i++) {
                if (this.isUploaderOss) {
                    // push进每一张所需要的上传的图片promise栈
                    uploadPromiseTask.push(that.uploadFile(file[i].url));
                } else {
                    // push进每一张所需要的上传的图片promise栈
                    uploadPromiseTask.push(file[i]);
                }
            }
            Promise.all(uploadPromiseTask)
                .then(res => {
                    that.fileList = that.fileList.concat(res);
                    // console.log('fileList', that.fileList);
                    uni.hideLoading();
                })
                .catch(err => {
                    console.log(err);
                    // 存在有上传失败的文件
                    uni.hideLoading();
                    uni.showToast({
                        title: '上传失败！',
                        icon: 'none'
                    });
                });
        },
        // 上传文件到线上
        uploadFile(uploadFile) {
            return new Promise((resolve, reject) => {
                const url = 'test';

                uploadImage(
                    uploadFile,
                    this.ossPathPrefix + url + '/',
                    // 上传成功
                    result => {
                        // console.log(result)
                        resolve({
                            url: result
                        });
                    },
                    // 上传失败
                    result => {
                        uni.showToast({
                            title: '上传失败',
                            icon: 'none'
                        });
                        // 这里写上传失败的代码
                        // console.log(JSON.stringify(result));
                    }
                );
            });
        },
        // 删除
        deleteImg(event) {
            const delIndex = event.detail.index,
                fileList = this.fileList;
            fileList.splice(delIndex, 1);
            this.fileList = fileList;
            this.$emit('uploadSuccess', this.fileList);
        },
        // 相机手动拍照上传
        getCamera() {
            const that = this;
            uni.chooseImage({
                count: that.maxCount, // 最多可以选择的图片张数，默认9
                sizeType: ['original', 'compressed'], // original 原图，compressed 压缩图，默认二者都有
                sourceType: that.capture, // album 从相册选图，camera 使用相机，默认二者都有。如需直接开相机或直接选相册，请只使用一个选项
                // 成功则返回图片的本地文件路径列表 tempFilePaths
                success: function(res) {
                    const file = res.tempFiles,
                        fileList = [];
                    for (let i = 0; i < file.length; i++) {
                        const element = file[i],
                            params = {
                                url: element.path,
                                size: element.size
                            };
                        fileList.push(params);
                    }
                    that.afterRead(fileList);
                }
            });
        },
        // 图片压缩
        imgCompress(file) {
            return new Promise((resolve, reject) => {
                if (file.size > this.compressMaxSize) {
                    this._imgCompress(file, resolve, reject);
                } else {
                    // console.log('compressMaxSize', file.size > this.compressMaxSize);
                    resolve(file);
                }
            });
        },
        _imgCompress(file, resolve, reject) {
            uni.showLoading({
                title: '正在压缩图片'
            });
            const that = this;
            uni.compressImage({
                src: file.url,
                quality: that.fileQuality, // 仅对jpg有效
                width: '50%',
                success: res => {
                    // console.log('compressImage', res);
                    // 文件转base64
                    pathToBase64(res.tempFilePath)
                        .then(base64 => {
                            const imgSize = that.imageSize(base64) * 1024,
                                params = {
                                    url: file.url,
                                    size: imgSize
                                };
                            if (imgSize > that.compressMaxSize) {
                                uni.hideLoading();
                                // console.log('fileQuality', that.fileQuality);
                                if (that.fileQuality < 10) {
                                    uni.showToast({
                                        icon: 'none',
                                        title: '图片过大,请重新选择',
                                        duration: 5000
                                    });
                                } else {
                                    that.fileQuality = (that.fileQuality - 20);
                                    that._imgCompress(params, resolve, reject);
                                }
                            } else {
                                uni.showToast({
                                    icon: 'none',
                                    title: '压缩成功'
                                });
                                resolve(params);
                            }

                            console.log('最终图片大小：', imgSize / 1024, 'KB');
                        })
                        .catch(error => {
                            console.error(error);
                            uni.showToast({
                                icon: 'none',
                                title: '转换失败'
                            });
                        });
                },
                fail: err => {
                    uni.showToast({
                        icon: 'none',
                        title: '压缩失败'
                    });
                    reject(err);
                },
                complete: () => {}
            });
        },
        // base64 获取文件大小
        imageSize(base64Str) {
            const tag = 'base64,',
                indexBase64 = base64Str.indexOf(tag);
            if (indexBase64 < 0) return -1;
            const str = base64Str.substr(indexBase64 + tag.length),
                // 计算文件流大小KB
                // const size = ((str.length - (str.length / 8) * 2) / 1024).toFixed(2) + 'KB'
                size = ((str.length * 0.75) / 1024).toFixed(2);
            return size;
        },
        // 添加水印
        addWaterMark(filePath) {
            return new Promise((resolve, reject) => {
                const that = this;
                uni.showLoading({
                    icon: 'none',
                    title: '正在添加水印'
                });
                uni.getImageInfo({// 获取图片信息
                    src: filePath,
                    success: res => {
                        that.canvasWidth = res.width;
                        that.canvasHeight = res.height;
                        // var ctx = uni.createCanvasContext('myCanvas'),
                        // 在自定义组件内 需要传递第二参数 this canvas才生效
                        var ctx = uni.createCanvasContext('myCanvas', this);
                        ctx.clearRect(0, 0, res.width, res.height);// 在给定的矩形内清除指定的像素。
                        ctx.beginPath();// 起始一条路径，或重置当前路径
                        ctx.drawImage(filePath, 0, 0, res.width, res.height);// 向画布上面绘制图片
                        // 为图片添加水印
                        ctx.translate(0, 0);// 重新映射画布上的 (0,0) 位置
                        // 这部分是水印的大小位置和数量
                        let imgWidth = '',
                            imgHeight = '';
                        if (res.width > res.height) {
                            imgWidth = res.width;
                            imgHeight = res.height;
                        } else {
                            imgWidth = res.height;
                            imgHeight = res.width;
                        }
                        // 水印的字体大小何位置计算
                        const fonstsize = (imgWidth / 40).toFixed(2),
                            textToWidth = imgWidth / 5 * 0.5,
                            textToHeight = (imgHeight / 8).toFixed(2) * 0.5;
                        // console.log('fonstsize---', fonstsize);
                        // console.log('textToWidth---', textToWidth);
                        // console.log('textToHeight---', textToHeight);
                        // 时间水印
                        let str = `时间：${new Date()}`,
                            lineWidth = fonstsize,
                            // 文本绘制的初始高度
                            initHeight = textToHeight,
                            // 绘制文本的高度
                            titleHeight = 100;
                            // 当前地点水印

                        str = str + `\r\n定位地点：当前位置`;
                        // 执行的工单类型水印
                        str = str + `\r\n工单类型：报修工单`;
                        ctx.setFillStyle('#ff0000');// 水印字体颜色
                        const fontSize1 = (fonstsize < 16 ? 16 : fonstsize);
                        ctx.setFontSize(fontSize1);// 水印字体大小
                        ctx.setTextAlign('left');// 水印字体位置
                        var textArray = str.split('\r\n');
                        // console.log(textArray);
                        // 对水印字符进行转行字符高度等判断（以此适配图片）
                        for (var j = 0; j < textArray.length; j++) {
                            var item = textArray[j],
                                isHeight = that.drawText(ctx, item, initHeight, titleHeight, textToHeight),
                                divideHeight = isHeight.split(',');
                            initHeight = Number(divideHeight[0]) + textToHeight;
                            titleHeight = Number(divideHeight[1]) + textToHeight;
                        }
                        // 开始绘制添加水印的图片并显示在页面中
                        ctx.draw(false, () => {
                            setTimeout(() => {
                                // canvas转文件
                                uni.canvasToTempFilePath({
                                    x: 0,
                                    y: 0,
                                    width: that.canvasWidth, // 画布宽度
                                    height: that.canvasHeight, // 画布高度
                                    destWidth: that.canvasWidth, // 输出图片宽度
                                    destHeight: that.canvasHeight, // 输出图片高度
                                    canvasId: 'myCanvas',
                                    fileType: 'jpg', // 目标文件的类型，只支持 'jpg' 或 'png'。默认为 'png'
                                    quality: 0.5, // 图片的质量，取值范围为 (0, 1]，不在范围内时当作1.0处理（如果不对此进行压缩，会导致图片很大）
                                    success: res => {
                                        uni.hideLoading();
                                        // 注意此时的地址是加了水印的图片地址（直接url输入浏览器也可以查看包含水印）
                                        // console.log('水印添加成功成功---', res);
                                        // 文件转base64
                                        pathToBase64(res.tempFilePath)
                                            .then(base64 => {
                                                const imgSize = that.imageSize(base64) * 1024,
                                                    params = {
                                                        size: imgSize,
                                                        url: res.tempFilePath
                                                    };

                                                console.log('最终图片大小：', (imgSize / 1024 / 1024).toFixed(2), 'M');
                                                if (that.isCompress) {
                                                    that.imgCompress(params, resolve, reject).then(res => {
                                                        resolve(res);
                                                    }).catch((err) => {
                                                        reject(err);
                                                    });
                                                } else {
                                                    resolve(params);
                                                }
                                            })
                                            .catch(error => {
                                                uni.showToast({
                                                    title: '文件转换失败',
                                                    icon: 'none'
                                                });
                                                console.error(error);
                                            });
                                    }
                                    // });
                                    // 在自定义组件内 需要传递第二参数 this canvas才生效
                                }, this);
                            }, 500);
                        });
                    },
                    fail: (e) => {
                        console.log(e);
                        uni.hideLoading();
                        uni.showToast({
                            title: '水印合成失败',
                            icon: 'none'
                        });
                    }
                });
            });
        },
        // canvans绘制多行文本，自动转行
        /*
        item：字符串，
        initHeight：初始高度
         */
        drawText: function(ctx, item, initHeight, titleHeight, textToHeight) {
            var lineWidth = 0,
                // 每次开始截取的字符串的索引
                lastSubStrIndex = 0;
            for (var i = 0; i < item.length; i++) {
                lineWidth += ctx.measureText(item[i]).width;
                if (lineWidth > (this.canvasWidth - textToHeight)) {
                // 绘制截取部分
                    ctx.fillText(item.substring(lastSubStrIndex, i), textToHeight, initHeight);
                    initHeight += textToHeight;
                    lineWidth = 0;
                    lastSubStrIndex = i;
                    titleHeight += textToHeight;
                }
                // 绘制剩余部分
                if (i == item.length - 1) {
                    ctx.fillText(item.substring(lastSubStrIndex, i + 1), textToHeight, initHeight);
                }
            }
            // console.log('结束一轮之后的initheight： ' + initHeight + ' titleHeight： ' + titleHeight);
            return initHeight + ',' + titleHeight;
        },
        // 视频压缩
        videoCompress(file) {
            console.log(file);
            return new Promise((resolve, reject) => {
                if (file.size > this.compressMaxSize) {
                    this._videoCompress(file, resolve, reject, 'medium');
                } else {
                    // console.log('compressMaxSize', file.size > this.compressMaxSize);
                    resolve(file);
                }
            });
        },
        _videoCompress(file, resolve, reject, quality) {
            uni.showLoading({
                title: '正在压缩视频...'
            });
            var that = this;
            uni.compressVideo({
                src: file.url,
                quality: quality, // 'low':低，'medium':中，'high':高
                success: res => {
                    console.log('压缩后', res);
                    uni.showToast({
                        title: '视频压缩成功',
                        icon: 'none'
                    }, 2000);
                    console.log('压缩后大小---', res.size / 1024 + 'M');
                    const params = {
                        url: res.tempFilePath,
                        size: res.size
                    };
                    // 压缩后的大小仍大于所设大小继续压缩
                    if ((res.size * 1024) > this.compressMaxSize) {
                        if (quality === 'medium') {
                            that._videoCompress(file, resolve, reject, 'low');
                        } else {
                            uni.showToast({
                                icon: 'none',
                                title: '视频太大，请重新选择'
                            });
                            resolve(params);
                        }
                    } else {
                        resolve(params);
                    }
                },
                fail: err => {
                    uni.showToast({
                        title: '视频压缩失败',
                        icon: 'none'
                    }, 2000);
                    console.log('error---', err);
                    reject(err);
                }
            });
        }
    }
};
</script>

<style scoped lang="less">
</style>

